﻿using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Linq;
using Net.Sgoliver.NRtfTree.Util;

namespace OWASP.CodeReview.CodeCrawler.Functionalities.Reports.Templates {
    /// <summary>
    /// RTF XML Integration
    /// Components : NRtfTree - A class library for RTF processing in C#
    ///              URL: http://www.codeproject.com/KB/string/nrtftree.aspx
    ///              
    /// </summary>
    internal class rtfTemplate {
        internal const string Description = "Description: ";
        internal const string Line = "Line: ";
        internal const string Threat = "Threat: ";


        public string Do(string dumpLocation, string outputPath, string reportName) {
            // Remove WhiteSpaces
            reportName = reportName.Trim();

            outputPath = CleanOutputPath(outputPath);

            // Ensure Reports Folder Exists
            EnsureReportsFolderExists(outputPath);

            // Create output Path
            RtfDocument rtfReport = createRtfOutputReport(string.Concat(outputPath, @"\", reportName));

            // Create Title Format
            RtfTextFormat titleFormat;
            HeaderTextFormat(out titleFormat);

            // Create Body Format
            RtfTextFormat format;
            simpleTextFormat(out format);

            // Create threatList Header Format
            RtfTextFormat threatHeader;
            ThreatHeaderTextFormat(out threatHeader);

            rtfReport.AddImage(Application.StartupPath + @"\\Images\\logo.png", 162, 30);

            IncludeEmptySpace(rtfReport);

            rtfReport.AddText("OWASP Code Crawler Report", titleFormat);
            IncludeEmptySpace(rtfReport);

            // .NET 3.5 Linq to XML

            if (string.IsNullOrEmpty(dumpLocation)) {
                MessageBox.Show("You must select a file in order to generate a report");
                return string.Empty;
            }


            XElement dumpXml = XElement.Load(dumpLocation);

            // Get Reference to Critical
            IEnumerable<XElement> criticalLevelCollection = from pn in dumpXml.Elements("ThreatList")
                                                            where pn.Element("Level").Value == "3"
                                                            select pn;
            // Get Reference to Medium
            IEnumerable<XElement> mediumLevelCollection = from pn in dumpXml.Elements("ThreatList")
                                                          where pn.Element("Level").Value == "2"
                                                          select pn;

            // Get Reference to Low
            IEnumerable<XElement> lowLevelCollection = from pn in dumpXml.Elements("ThreatList")
                                                       where pn.Element("Level").Value == "1"
                                                       select pn;


            /// Show list only if critical are present
            if (criticalLevelCollection.Count() > 0) {
                rtfReport.AddText("Critical Level", threatHeader);
                IncludeEmptySpace(rtfReport);

                // Create Critical Threat List
                createCriticalThreatDescription(rtfReport, format, threatHeader, criticalLevelCollection);
            }


            /// Show list only if medium are present
            if (mediumLevelCollection.Count() > 0) {
                rtfReport.AddText("Medium Level", threatHeader);
                IncludeEmptySpace(rtfReport);

                // Create Medium Threat List
                createMediumLevelThreatDescription(rtfReport, format, threatHeader, mediumLevelCollection);
            }

            /// Show list only if low are present
            if (lowLevelCollection.Count() > 0) {
                rtfReport.AddText("Low Level", threatHeader);
                IncludeEmptySpace(rtfReport);

                // Create Low Threat List
                createLowLevelThreatDescription(rtfReport, format, threatHeader, lowLevelCollection);
            }


            try {
                rtfReport.Close();
            }
            catch (IOException) {
                MessageBox.Show("Please choose another name for this report");
            }

            return string.Concat(outputPath, @"\", reportName);
        }


        private static void IncludeEmptySpace(RtfDocument rtfReport) {
            rtfReport.AddNewLine();
            rtfReport.AddNewLine();
        }

        #region Format Result
        /// <summary>
        /// This will create a list containing all the Critical Threats found within the Dump File
        /// </summary>
        /// <param name="rtfReport">RtfDocument</param>
        /// <param name="format">RtfTextFormat</param>
        /// <param name="threatHeader">RtfTextFormat</param>
        /// <param name="criticalLevelCollection">IEnumerable-XElement-</param>
        internal static void createCriticalThreatDescription(RtfDocument rtfReport, RtfTextFormat format,
                                                             RtfTextFormat threatHeader,
                                                             IEnumerable<XElement> criticalLevelCollection) {
            foreach (XElement criticalLevelThreat in criticalLevelCollection) {
                rtfReport.AddText(string.Concat(Threat, criticalLevelThreat.Element("Threat").Value), threatHeader);
                rtfReport.AddNewLine();
                rtfReport.AddText(string.Concat(Line, criticalLevelThreat.Element("Line").Value), format);
                rtfReport.AddNewLine();
                rtfReport.AddText(string.Concat(Description, criticalLevelThreat.Element("Description").Value), format);
                rtfReport.AddNewLine();
                rtfReport.AddNewLine();
            }
        }


        /// <summary>
        /// This will create a list containing all the Medium Threats found within the Dump File
        /// </summary>
        /// <param name="rtfReport">RtfDocument</param>
        /// <param name="format">RtfTextFormat</param>
        /// <param name="threatHeader">RtfTextFormat</param>
        /// <param name="mediumLevelCollection">IEnumerable-XElement-</param>
        private static void createMediumLevelThreatDescription(RtfDocument rtfReport, RtfTextFormat format,
                                                               RtfTextFormat threatHeader,
                                                               IEnumerable<XElement> mediumLevelCollection) {
            foreach (XElement mediumLevelThreat in mediumLevelCollection) {
                rtfReport.AddText(string.Concat(Threat, mediumLevelThreat.Element("Threat").Value), threatHeader);
                rtfReport.AddNewLine();
                rtfReport.AddText(string.Concat(Line, mediumLevelThreat.Element("Line").Value), format);
                rtfReport.AddNewLine();
                rtfReport.AddText(string.Concat(Description, mediumLevelThreat.Element("Description").Value), format);
                rtfReport.AddNewLine();
                rtfReport.AddNewLine();
            }
        }


        /// <summary>
        /// This will create a list containing all the Low Threats found within the Dump File
        /// </summary>
        /// <param name="rtfReport">RtfDocument</param>
        /// <param name="format">RtfTextFormat</param>
        /// <param name="threatHeader">RtfTextFormat</param>
        /// <param name="lowLevelCollection">IEnumerable-XElement-</param>
        private static void createLowLevelThreatDescription(RtfDocument rtfReport, RtfTextFormat format,
                                                            RtfTextFormat threatHeader,
                                                            IEnumerable<XElement> lowLevelCollection) {
            foreach (XElement lowLevelThreat in lowLevelCollection) {
                rtfReport.AddText(string.Concat(Threat, lowLevelThreat.Element("Threat").Value), threatHeader);
                rtfReport.AddNewLine();
                rtfReport.AddText(string.Concat(Line, lowLevelThreat.Element("Line").Value), format);
                rtfReport.AddNewLine();
                rtfReport.AddText(string.Concat(Description, lowLevelThreat.Element("Description").Value), format);
                rtfReport.AddNewLine();
                rtfReport.AddNewLine();
            }
        }
        #endregion

        #region System.IO
        /// <summary>
        /// Output Folder Exists
        /// </summary>
        /// <param name="outputPath"></param>
        private static void EnsureReportsFolderExists(string outputPath) {
            var generatedFolder = new DirectoryInfo(outputPath);
            if (!generatedFolder.Exists) generatedFolder.Create();
        }
        #endregion

        #region System.String
        /// <summary>
        /// Remove Unecessary Chars
        /// </summary>
        /// <param name="outputPath"></param>
        /// <returns></returns>
        private static string CleanOutputPath(string outputPath) {
            outputPath = outputPath.Replace(@"/", @"\\");
            outputPath = outputPath.Replace(@"\\\", @"\\");
            outputPath = outputPath.Replace(@"\\", @"\");
            return outputPath;
        }
        #endregion

        #region Utility
        /// <summary>
        /// </summary>
        /// <param name="outputPath"></param>
        /// <returns></returns>
        private static RtfDocument createRtfOutputReport(string outputPath) {
            outputPath = outputPath.Replace("xml", "rtf");
            var document = new RtfDocument(outputPath);
            return document;
        }
        #endregion

        #region Styles
        /// <summary>
        /// Create Body Style
        /// </summary>
        /// <param name="format"></param>
        private void simpleTextFormat(out RtfTextFormat format) {
            format = new RtfTextFormat();
            format.size = 9;
            format.bold = false;
            format.underline = false;
            format.font = "Arial";
        }


        /// <summary>
        /// Create Header Style
        /// </summary>
        /// <param name="format"></param>
        private static void HeaderTextFormat(out RtfTextFormat format) {
            format = new RtfTextFormat();
            format.size = 12;
            format.bold = true;
            format.underline = false;
            format.font = "Arial";
            format.color = Color.Black;
        }


        /// <summary>
        /// Create Header Style
        /// </summary>
        /// <param name="format"></param>
        private static void ThreatHeaderTextFormat(out RtfTextFormat format) {
            format = new RtfTextFormat();
            format.size = 10;
            format.bold = true;
            format.underline = false;
            format.font = "Arial";
            format.color = Color.Blue;
        }
        #endregion
    }
}